﻿/*======================================================================
== Copyright : BlueCurve (c)
== Licence   : Gnu/GPL v2.x
== Author    : Teddy Albina
== Email     : bluecurveteam@gmail.com
== Web site  : http://www.codeplex.com/BlueCurve
========================================================================*/
using System.IO;
using System.Xml.Linq;
using HtmlAgilityPack;

namespace BlueCurve.Common.HtmlAgilityPackExtension
{
    /// <summary>
    /// Class contenant des méthodes
    /// d'extentsion pour Htmlagilitypack
    /// </summary>
    public static class HtmlAgilityPackExtension
    {
        /// <summary>
        /// Convert HtmlDocument to XDocument
        /// </summary>
        /// <example>
        /// <![CDATA[
        /// The first step is to download a page and convert it's HtmlDocument object graph into an XDocument.
        /// HtmlWeb hw = new HtmlWeb();
        /// string url = @"http://www.nytimes.com/2008/05/18/us/politics/18memoirs.html?hp";
        /// Uri uri = new Uri(url);
        /// HtmlDocument doc = hw.Load(url);
        /// var xdoc = doc.ToXDocument();
        /// 
        /// Now we can find all the image tags with a simple LINQ expression.
        /// var imgs = from el in xdoc.Descendants()
        ///            where el.Name.LocalName == "img"
        ///            select new
        ///            {
        ///                Src = el.Attribute(XName.Get("src")).Value,
        ///            };
        ///           
        /// 
        /// 
        /// Every raster image has a width and height, even if the image tag doesn't.
        /// If the size cannot be seen on the tag, we could download and open the image to find out it's true height/width.
        /// A fast way to do this would be read the image header,
        /// but this post isn't about the Image class or reading images - just LINQ to HTML. 
        /// For now, I'm going to create a default width and height of 0.
        /// 
        /// XName widthAttribute = XName.Get("width");
        /// XName heightAttribute = XName.Get("height");
        /// XName srcAttribute = XName.Get("src");
        /// XAttribute defaultHeight = new XAttribute(heightAttribute, "0");
        /// XAttribute defaultWidth = new XAttribute(widthAttribute, "0");
        /// 
        /// 
        /// Now we can read the width and height in the LINQ expression allowing for defaults,
        /// and adding a hack for sizes expressed in percentages.
        /// 
        /// var imgs =
        /// from el in xdoc.Descendants()
        /// let width = Int32.Parse((el.Attribute(widthAttribute) ?? defaultWidth).Value.TrimEnd('%'))
        /// let height = Int32.Parse((el.Attribute(heightAttribute) ?? defaultHeight).Value.TrimEnd('%'))
        /// let metric = Math.Sqrt(width * height)
        /// where el.Name.LocalName == "img"         orderby metric descending         select          new { 
        ///     Src = el.Attribute(srcAttribute).Value,
        ///     Width = width,
        ///     Height = height
        /// };
        ///
        ///
        /// foreach (var image in imgs)
        /// {
        ///     Console.WriteLine("{0} Size: {1}x{2}", 
        ///     image.Src, 
        ///     image.Width, 
        ///     image.Height);
        /// }]]>
        /// </example>
        /// <param name="document">Objet HtmlDocument à convertir en XDocument</param>
        /// <returns>XDocument</returns>
        public static XDocument ToXDocument(this HtmlDocument document)
        {
            try
            {
                using (StringWriter sw = new StringWriter())
                {
                    document.OptionOutputAsXml = true;
                    document.Save(sw);
                    return XDocument.Parse(sw.GetStringBuilder().ToString());
                }
            }
            catch
            {
                return null;
            }
        }
    }
}
